﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using senac.ws.interfaces;
using System.Data;
using senac.util;
using System.Data.SqlClient;
using System.Data.OleDb;

namespace senac.ws.DAO
{
    public class BaseDeDados : IBaseDeDados
    {
        #region Singleton
        private static BaseDeDados instance;

        private BaseDeDados() { }

        public static BaseDeDados Instance
        {
            get 
            {
                if (instance == null)
                    instance = new BaseDeDados();

                return instance;
            }
        }
        #endregion

        //Nome das colunas que serão tipo INT
        List<string> colunasTipoInt = new List<string>() { "CODIGOUO", "CODIGOTURMA", "CARGAHORARIA", "ANO", "PARCELAS", "PARTICIPANTES", "CODAMBIENTEPEDAGOGICOREDEFIS" };

        /// <summary>
        /// Responsável por retornar a string de conexão com o banco
        /// </summary>
        private string strConn
        {
            //get { return @"Provider=SQLOLEDB;Data Source=10.9.8.9;Password=usr674532#5;User ID=intrausuario;Initial Catalog=Intranet"; }
            get { return @"Data Source=10.9.8.9;Password=usr674532#5;User ID=intrausuario;Initial Catalog=Intranet"; }
        }

        /// <summary>
        /// Responsável por ir no banco de dados e verificar se uma determinada tabela existe por lá
        /// </summary>
        public void VerificarTabelaNoBanco()
        {
            Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Verificando existência de tabela...");

            try
            {
                //Select para verificar se determinada tabela existe no banco de dados
                string verifyTableExist = @"SELECT name
                                            FROM SYSOBJECTS
                                            WHERE XTYPE = 'U'
                                            AND NAME = 'PSGDadosDeTurmasParaPublicarNaInternet'";

                DataTable dtExistTable = executarQuery(verifyTableExist);

                //Verifica se foi encontrada alguma tabela na base
                if (dtExistTable.Rows.Count == 1)
                {
                    Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Tabela encontrada...");
                    Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Apagando tabela...");

                    //Caso tenha sido encontrada, ela será apagada
                    executarQuery("DROP TABLE PSGDadosDeTurmasParaPublicarNaInternet;");
                }
                else
                    Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Tabela não encontrada!");
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Responsável por criar a tabela no banco de dados.
        /// </summary>
        /// <param name="dt">DataTable com a tabela de retorno do método do Web Service do Mira</param>
        /// <returns>Lista com o nome de todas as colunas criadas na tabela</returns>
        public List<string> CriarTabela(DataTable dt)
        {
            //Lista com o nome de todas as colunas que servirão de retorno pra este método
            List<string> listColunas = new List<string>();

            try
            {
                Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Criando nova tabela...");

                StringBuilder sbCreate = new StringBuilder();

                //Criando instrução sql para a criação da tabela
                sbCreate.Append("CREATE TABLE PSGDadosDeTurmasParaPublicarNaInternet ( pkId INT IDENTITY,");

                //Definindo o tipo das colunas que serão criadas
                foreach (DataColumn coluna in dt.Columns)
                {
                    if (colunasTipoInt.Contains(coluna.ColumnName))
                        sbCreate.Append(coluna.ColumnName + " INT,");
                    else if (coluna.ColumnName.Equals("PSG") || coluna.ColumnName.Equals("PRONATEC"))
                        sbCreate.Append(coluna.ColumnName + " NVARCHAR(10),");
                    else
                        sbCreate.Append(coluna.ColumnName + " TEXT,");
                    
                    listColunas.Add(coluna.ColumnName);
                }

                //Retirando a última vírgula da cláusula e fechando a instrução
                string createTable = sbCreate.ToString().Remove(sbCreate.Length - 1, 1) + ");";

                executarQuery(createTable);

                Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Tabela criada!");
            }
            catch
            {
                throw;
            }

            return listColunas;
        }

        /// <summary>
        /// Responsável por popular a tabela. Cria toda instrução de insert para o banco.
        /// </summary>
        /// <param name="listColunas">Lista com o nome de todas as colunas que existem na tabela que será populada</param>
        /// <param name="dt">DataTable com tabela de retorno do método no WebService do Mira</param>
        public void PopularTabela(List<string> listColunas, DataTable dt)
        {
            try
            {
                Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Populando tabela...");

                //Criando início do comando insert
                StringBuilder sbPopulate = new StringBuilder();
                sbPopulate.Append("INSERT INTO intrausuario.PSGDadosDeTurmasParaPublicarNaInternet (");

                //Inserindo o nome das colunas no comando insert
                for (int i = 0; i < listColunas.Count; i++)
                {
                    if (i != (listColunas.Count - 1))
                        sbPopulate.Append(listColunas[i].ToString() + ",");
                    else
                        sbPopulate.Append(listColunas[i].ToString() + ") VALUES (");
                }

                List<string> listInsert = new List<string>();
                StringBuilder sbInsert = null;

                //Preenchendo o comando insert com o valores necessários
                foreach (DataRow linha in dt.Rows)
                {
                    sbInsert = new StringBuilder();

                    //Inserindo o início do comando insert, criado no bloco de código anterior
                    sbInsert.Append(sbPopulate.ToString());
                    for (int i = 0; i < listColunas.Count; i++)
                    {
                        if (i != (listColunas.Count - 1))
                        {
                            if (colunasTipoInt.Contains(listColunas[i].ToString()))
                                sbInsert.Append("" + linha[listColunas[i].ToString()].ToString() + ",");
                            else
                                sbInsert.Append("'" + linha[listColunas[i].ToString()].ToString().Replace("'", "''") + "',");
                        }
                        else
                            sbInsert.Append("'" + linha[listColunas[i].ToString()].ToString().Replace("'", "''") + "');");
                    }
                    listInsert.Add(sbInsert.ToString());
                }

                //Inserindo todos os comandos inserts em apenas uma variável
                StringBuilder querycompleta = new StringBuilder();
                foreach (string insert in listInsert)
                    querycompleta.Append(insert);

                //Executando query para inserir os registros no banco
                executarQuery(querycompleta.ToString());

                Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Tabela Populada!");
                Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Verificando quantidade de registros inseridos...");

                //Executando query para verificar se os registros foram incluídos
                DataTable dtResultadoInsert = executarQuery("SELECT COUNT(pkId) FROM intrausuario.PSGDadosDeTurmasParaPublicarNaInternet");

                if (dtResultadoInsert != null && dtResultadoInsert.Rows.Count > 0)
                {
                    string msg = "Total inserido na base local: " + dtResultadoInsert.Rows[0][0].ToString();
                    Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, msg);
                }
                else
                {
                    Util.Instance.EscreverLog(Util.opcoesEscrita.EscreverMensagem, "Total inserido na base local: 0");
                }
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Método para efetuar a conexão com o banco de dados e executar a query passada por parâmetro
        /// </summary>
        /// <param name="query">string com a query a ser executada no banco de dados</param>
        /// <returns>Tabela com as informações recuperadas</returns>
        private DataTable executarQuery(string query)
        {
            DataTable dt = new DataTable();
            SqlConnection conn = new SqlConnection(strConn);
            
            try
            {
                SqlCommand command = new SqlCommand(query, conn);
                SqlDataAdapter adapter = new SqlDataAdapter(command);
                adapter.Fill(dt);
            }
            catch { throw; }
            finally { conn.Close(); }

            return dt;
        }
    }
}
